package com.mall.common.aspect;

import com.mall.common.annotation.CacheFind;
import com.mall.common.util.ObjectMapperUtil;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;

import java.util.Arrays;

@Component
@Aspect
public class RedisAspect {

    @Autowired
    private Jedis jedis;

    //@Around("@annotation(com.mall.common.annotation.CacheFind)")
    public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind) throws Throwable {

        String perkey = cacheFind.key();   // 获取注解的属性
        String args = Arrays.toString(joinPoint.getArgs());
        String key = perkey + "::" + args;   // 拼接成redis的key


        Object result = null;
        //2.判断redis中是否有数据
        if(jedis.exists(key)){
            String json = jedis.get(key);

            //利用工具API动态获取返回值类型  // MethodSignature是Signature(签名)的子类，所以进行强转
            MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
            Class returnType = methodSignature.getReturnType();   // 获取目标函数的返回值的类型的.class文件
            //如果采用object.class形式 则只能转化简单对象,不能转化嵌套对象，像List<<Map<key,value>>>这样的就转化不了了
            // result = ObjectMapperUtil.toObj(json,Object.class);  像List<<Map<key,value>>>这样的就转化不了了

            result = ObjectMapperUtil.toObj(json,returnType);  // 将json对象转换成普通对象
            System.out.println("AOP查询Redis缓存!!!");

        }else{
            //表示缓存中没有数据,应该查询数据库动态获取
            result = joinPoint.proceed();    //调用下一个通知/目标方法
            //应该将数据保存到缓存中
            String json = ObjectMapperUtil.toJSON(result);  // 将对象转换为json
            if(cacheFind.seconds()>0){
                jedis.setex(key, cacheFind.seconds(), json);
            }else{
                jedis.set(key,json);
            }
            System.out.println("AOP查询数据库!!!");
        }

        return result;
    }

}
